package com.hzdp.web.ops.remote;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

public class RemoteIpGetter {
	/**
	 * 出错时返回的IP地址
	 */
	public static final String FAIL_IP_RESULT = "127.0.0.1";
	/**
	 * 非法IP的数字表达
	 */
	public static final int WRONG_IP_NUMBER = -1;
	/**
	 * 代理IP段，即非用户IP
	 */
	public static final List<IpScope> PROXY_SCOPES = new ArrayList<IpScope>();

	static {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					RemoteIpGetter.class.getResourceAsStream("/proxy.txt")));
			if (reader != null) {
				String data = null;
				while ((data = reader.readLine()) != null) {
					IpScope scope = IpScope.getIpScope(data);
					if (scope.startIp >= 0) {
						PROXY_SCOPES.add(scope);
					}
				}
			}
		} catch (Exception ex) {
		}
	}

	/**
	 * 获取SLB的remote_addr，算法为取x-forwarded-for中最后一个外网IP
	 * 
	 * @param request
	 *            servlet请求的request对象
	 * @return
	 */
	public static String getRemoteAddr(HttpServletRequest request) {
		try {
			return getRemoteAddr(getXForwardedFor(request));
		} catch (Exception ex) {
			return request.getRemoteAddr();
		}
	}

	/**
	 * 获取x-forwarded-for中第一个用户外网IP地址
	 * 
	 * @param request
	 *            servlet请求的request对象
	 * @return
	 */
	public static String getFirstGlobalAddr(HttpServletRequest request) {
		try {
			return getFirstGlobalAddr(getXForwardedFor(request));
		} catch (Exception ex) {
			return request.getRemoteAddr();
		}
	}

	/**
	 * 获取x-forwarded-for
	 * 
	 * @param request
	 *            servlet请求的request对象
	 * @return
	 */
	public static String getXForwardedFor(HttpServletRequest request) {
		try {
			String ip = request.getHeader("X-Forwarded-For");
			if (ip == null || ip.trim().length() == 0
					|| "unknown".equalsIgnoreCase(ip.trim())) {
				return request.getRemoteAddr();
			}
			return ip.trim();
		} catch (Exception ex) {
			return request.getRemoteAddr();
		}
	}

	/**
	 * 计算x-forwarded-for中的remote_addr，即SLB的remote_addr，算法为取最后一个外网IP
	 * 
	 * @param xForwardedFor
	 *            HTTP头中的x-forwarded-for字段，可以通过getXForwardedFor方法获取
	 * @return
	 */
	public static String getRemoteAddr(String xForwardedFor) {
		try {
			String trimXff = xForwardedFor.trim();
			String[] ipArray = trimXff.split(",");
			if (ipArray.length == 0) {
				return trimXff;
			}
			for (int i = ipArray.length - 1; i >= 0; i--) {
				String ip = ipArray[i].trim();
				try {
					if (isHostIp(ip)) {
						return ip;
					}
				} catch (Exception ex) {
				}
			}

			// 第一个地址为代理地址，则认为是代理已经变化，返回第一个地址
			if (isProxyIp(ipArray[0].trim())) {
				return ipArray[0].trim();
			}

			return FAIL_IP_RESULT;
		} catch (Exception ex) {
			return FAIL_IP_RESULT;
		}
	}

	/**
	 * 计算x-forwarded-for中第一个用户外网IP地址
	 * 
	 * @param xForwardedFor
	 *            HTTP头中的x-forwarded-for字段，可以通过getXForwardedFor方法获取
	 * @return
	 */
	public static String getFirstGlobalAddr(String xForwardedFor) {
		try {
			String trimXff = xForwardedFor.trim();
			String[] ipArray = trimXff.split(",");
			if (ipArray.length == 0) {
				return trimXff;
			}
			for (String ip : ipArray) {
				String trimIp = ip.trim();
				try {
					if (isHostIp(trimIp)) {
						return trimIp;
					}
				} catch (Exception ex) {
				}
			}
			if (isIp(ipArray[0])) {
				return ipArray[0];
			}
			return FAIL_IP_RESULT;
		} catch (Exception ex) {
			return FAIL_IP_RESULT;
		}
	}

	/**
	 * 获取x-forwarded-for中所有外网IP地址列表
	 * 
	 * @param xForwardedFor
	 *            HTTP头中的x-forwarded-for字段，可以通过getXForwardedFor方法获取
	 * @return
	 */
	public static List<String> getAllGlobalIp(String xForwardedFor) {
		try {
			List<String> result = new ArrayList<String>();
			String trimXff = xForwardedFor.trim();
			String[] ipArray = trimXff.split(",");
			for (String ip : ipArray) {
				String trimIp = ip.trim();
				try {
					if (isHostIp(trimIp)) {
						result.add(trimIp);
					}
				} catch (Exception ex) {
				}
			}
			return result;
		} catch (Exception ex) {
			return new ArrayList<String>();
		}
	}

	/**
	 * 判断一个字符串是否为IP地址
	 * 
	 * @param input
	 * @return
	 */
	public static boolean isIp(String input) {
		return isIp(getIpNumber(input));
	}

	protected static boolean isIp(long ipNumber) {
		return ipNumber >= 0;
	}

	/**
	 * 判断一个字符串是否为内网IP地址，内网IP网段如下所示。如果字符串不是合法的IP地址，返回false<br>
	 * 10.0.0.0~10.255.255.255 <br>
	 * 172.16.0.0~172.31.255.255 <br>
	 * 192.168.0.0~192.168.255.255
	 * 
	 * @param input
	 * @return
	 */
	public static boolean isNatIp(String input) {
		try {
			if (!isIp(input)) {
				return false;
			}
			long ipNumber = getIpNumber(input);
			return isNatIp(ipNumber);
		} catch (Exception ex) {
			return false;
		}
	}

	protected static boolean isNatIp(long ipNumber) {
		// 10.0.0.0~10.255.255.255
		if (ipNumber >= 167772160 && ipNumber < 184549376) {
			return true;
		}
		// 172.16.0.0~172.31.255.255
		if (ipNumber >= 2886729728L && ipNumber < 2887778304L) {
			return true;
		}
		// 192.168.0.0~192.168.255.255
		if (ipNumber >= 3232235520L && ipNumber < 3232301056L) {
			return true;
		}
		return false;
	}

	public static boolean isProxyIp(String input) {
		try {
			if (!isIp(input)) {
				return false;
			}
			long ipNumber = getIpNumber(input);
			return isProxyIp(ipNumber);
		} catch (Exception ex) {
			return false;
		}
	}

	protected static boolean isProxyIp(long ipNumber) {
		for (IpScope scope : ProxyConfig.getProxy()) {
			if (scope.isInScope(ipNumber)) {
				return true;
			}
		}
		return false;
	}

	protected static boolean isHostIp(String ip) {
		long ipNumber = getIpNumber(ip);
		return ipNumber >= 0 && !isNatIp(ipNumber) && !isProxyIp(ipNumber);
	}

	protected static long getIpNumber(String input) {
		try {
			String[] subIps = input.split("\\.");
			if (subIps.length != 4) {
				return WRONG_IP_NUMBER;
			}
			long result = 0;
			for (String subIp : subIps) {
				int subIpInt;
				try {
					subIpInt = Integer.parseInt(subIp);
				} catch (Exception ex) {
					return WRONG_IP_NUMBER;
				}
				if (subIpInt < 0 || subIpInt > 255) {
					return WRONG_IP_NUMBER;
				}
				result *= 256;
				result += subIpInt;
			}
			return result;
		} catch (Exception ex) {
			return WRONG_IP_NUMBER;
		}
	}
}
